<?php
/*
 * Copyright 2009, Jeffrey Palm.
 */

include_once 'util.php';

class TestCase {
  function TestCase($name,$reason,$isFailure) {
    $this->name = $name;
    $this->reason = $reason;
    $this->isFailure = $isFailure;
  }
}

class TestFailure extends TestCase {
  function TestFailure($name,$reason) {
    $this->TestCase($name,$reason,TRUE);
  }
}

class TestPass extends TestCase {
  function TestPass($name,$reason) {
    $this->TestCase($name,$reason,FALSE);
  }
}

class TestRunner {
  function TestRunner() {
    $this->currentFunction = NULL;
    $this->failures = array();
    $this->passes = array();
    $this->testNames = array();
    $this->testNamesRun = array();
  }

  function addTest($name) {
    $this->testNames []= $name;
  }

  function addFailure($reason=NULL) {
    $this->failures []= new TestFailure($this->currentFunction,$reason);
  }

  function addPass($reason=NULL) {
    $this->passes []= new Testpass($this->currentFunction,$reason);
  }

  function runTest($name) {
    $this->currentFunction = $name;
    $name();
    $this->testNamesRun[$name] = TRUE;
  }

  function printArray($title,$arr) {
    echo $title . ": " . count($arr) . "\n";
    for ($i=0; $i<count($arr); $i++) {
      $t = $arr[$i];
      echo '[' . $i . '] ' . $t->name . ': ' . 
				($t->reason ? $t->reason : '(NULL)') . "\n";
    }
  }
  
  function printResults() {

    $fail = FALSE;

    echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
    echo "Test results\n";
    
    // Make sure all the test cases were run
    foreach ($this->testNames as $tn) {
      if (!$this->testNamesRun[$tn]) {
        echo "ERROR: ". $tn . " wasn't run\n";
        $fail = TRUE;
      }
    }

    // Print all the passes and failures
    //no $this->printArray('Passes',$this->passes);
    $this->printArray('Failures',$this->failures);

    $passed = count($this->passes);
    $total = $passed + count($this->failures);
    $percent = $total == 0 ? 100.0 : 100.0 * $passed / $total;
    printf('TOTAL: ' . $passed . '/' . $total . ' = %%%.2f', $percent);
    echo "\n";

    echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";

    exit($fail ? 1 : 0);
  }
}

// ----------------------------------------------------------------------
// The global test runner
// ----------------------------------------------------------------------
$runner = new TestRunner();

// ----------------------------------------------------------------------
// Functions for the test cases to use
// ----------------------------------------------------------------------

function assertion($b,$reason=NULL) {
  global $runner;
  if (!$b) {
    $runner->addFailure($reason);
  } else {
    $runner->addPass($reason);
  }
}

/**
 * Finds all the tests in the current file and runs them.
 */
function runTests() {

  global $runner;

  // Find all the tests in *all* the files
	$handle = opendir('.');
	while (false !== ($file = readdir($handle))) {
		if (!preg_match('/\.php$/',$file)) continue;
		
		// Do one include for every file that actually has a function being run
		$printedInclude = FALSE;

		$lines = file($file);
		$names = array();
		foreach ($lines as $line) {
			if (preg_match('/function (test\w+)\(/',$line,$out)) {
				$testName = $out[1];
				$runner->addTest($testName);
				$names []= $testName;
				if (!$printedInclude) {
					include $file;
					$printedInclude = TRUE;
				}
			}
		}
	}
  
  // Run all the tests
  foreach ($names as $n) {
    $runner->runTest($n);
  }

  // Print the results
  $runner->printResults();
}

?>